package io.yuanqi.hgtcshop.service.impl;

import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.net.URLEncoder;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import io.yuanqi.hgtcshop.controller.share.ShareController;
import io.yuanqi.hgtcshop.entity.dos.Order;
import io.yuanqi.hgtcshop.entity.enums.*;
import io.yuanqi.hgtcshop.entity.model.Amount;
import io.yuanqi.hgtcshop.entity.model.Payer;
import io.yuanqi.hgtcshop.entity.model.UnifiedOrderModel;
import io.yuanqi.hgtcshop.entity.model.WechatPaymentSetting;
import io.yuanqi.hgtcshop.entity.param.DFPayParam;
import io.yuanqi.hgtcshop.entity.param.PayParam;
import io.yuanqi.hgtcshop.entity.param.PaymentSuccessParams;
import io.yuanqi.hgtcshop.entity.response.PaymentHttpResponse;
import io.yuanqi.hgtcshop.entity.vo.ResultMessage;
import io.yuanqi.hgtcshop.entity.vo.UserNameAndFaceVO;
import io.yuanqi.hgtcshop.exception.ServiceException;
import io.yuanqi.hgtcshop.service.OrderService;
import io.yuanqi.hgtcshop.service.PayService;
import io.yuanqi.hgtcshop.utils.CurrencyUtil;
import io.yuanqi.hgtcshop.utils.DateTimeZoneUtil;
import io.yuanqi.hgtcshop.utils.ResultUtil;
import io.yuanqi.hgtcshop.utils.SnowFlake;
import io.yuanqi.hgtcshop.wechat.WechatApi;
import io.yuanqi.hgtcshop.wechat.kit.AesUtil;
import io.yuanqi.hgtcshop.wechat.kit.HttpKit;
import io.yuanqi.hgtcshop.wechat.kit.PayKit;
import io.yuanqi.hgtcshop.wechat.kit.WxPayKit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

import static io.yuanqi.hgtcshop.controller.share.ShareController.WEB_GET_ACCESS_TOKEN;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @Autowired
    private OrderService orderService;
//
//    @Autowired
//    private WeChatPayService weChatPayService;
//    @Autowired
//    private ShareController shareController;

    @Value("${weixin.appId}")
//    @Value("${some.key:my default value}")
    private String appid;

    @Value("${weixin.secret}")
    private String secret;

    @Value("${wechat.mchId}")
    private String mchId;

    @Value("${wechat.serialNumber}")
    private String serialNumber;

    @Value("${wechat.ApiKey3}")
    private String ApiKey3;

//    private static final String appid = "wx0fa1500017b8f6f1";
//    private static final String mchId =  "1675168756"; //1675168756
//    private static final String serialNumber = "2EAC8EA6E93391EAA4D055C13B3C5D0ACA419470";
    private static final String appliclient_key = "apiclient_key.pem";

//    private final static String ApiKey3 = "MrvvZ3kYgJDYh9OFCUoDpp5wgUQKIbES";
    private static final String NOTIFY_URL = "https://m.hgtc.shop/hgtc/buyer/payment/cashier/pay/notify";

    @Value("${weixin.appid}")
    private String appId;



    @Override
    public ResultMessage<Object> jsApiPay(PayParam payParam) {
        try {
            String orderSn = payParam.getOrderSn();
            Payer payer = new Payer();
            UserNameAndFaceVO userNameAndFaceByOrderSn = orderService.getUserNameAndFaceByOrderSn(orderSn);
            log.info(".jsApiPay userNameAndFaceByOrderSn:{}", userNameAndFaceByOrderSn);
            payer.setOpenid(userNameAndFaceByOrderSn.getOpenId());

            Order order = orderService.getOrder(orderSn);
            log.info(".jsApiPay order:{}", order);


            //支付金额
            Integer fen = CurrencyUtil.fen(order.getFlowPrice());
            //第三方付款订单
            String outOrderNo = SnowFlake.createStr("pay_");

            // 将payOrder 更新到订单中
            orderService.updatePayOrderSnByOrderSn(orderSn, outOrderNo);

            //过期时间
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);

            String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(payParam), StandardCharsets.UTF_8);


            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(appid)
                    .setMchid(mchId)
                    .setDescription("aa")
                    .setOut_trade_no(outOrderNo)
                    .setTime_expire(timeExpire)
                    .setAttach(attach)
                    .setNotify_url(NOTIFY_URL)
                    .setAmount(new Amount().setTotal(fen))
                    .setPayer(payer);

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            PaymentHttpResponse response = WechatApi.v3(
                    RequestMethodEnums.POST,
                    WechatDomain.CHINA.toString(),
                    WechatApiEnum.JS_API_PAY.toString(),
                    mchId,
                    serialNumber,
                    null,
                    appliclient_key,
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            //根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, getPlatformCert());
            log.info("verifySignature: {}", verifySignature);
            log.info("统一下单响应 {}", response);

            if (verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, appliclient_key);


//                String json = "{\"timeStamp\":\"1707227342\",\"signType\":\"RSA\",\"package\":\"prepay_id=wx062149024993563e099438072054070000\",\"paySign\":\"0b00/0rNFkVpKWZhVDzZwPzbGjiedSOmhZ544iwmoh9ocmTOigYD06H9X5pTgQ58GUrXfSO8Z7xRdmU2gGfZIQx8KUXbYKuCjdfMEWK+GCZ8K7qU2cv7l2ulxbVCgKyYrFIhUED2sdIJV2bT19yaGeToDI6rqP92TpVIlRiip5Xe9/5YTqyi7e7Mg0+JpvlsnUkPfxCO5UJvc0jh/Gd94FwaJhVA8F53DWjzX5sIIREoqujNlVqARLS1ypGZWuPPwunOUMtpj9uWO5oaF3thwmOT0zyned/gUMNNZxezQwRr83uGV4VhGySo1ElNsdXYZdS4f5Fu8OQSxoFpgrPJIg==\",\"nonceStr\":\"1707227342156\",\"appId\":\"wx0fa1500017b8f6f1\"}";
//
//
//                Gson gson = new Gson();
//                Type type = new TypeToken<Map<String, String>>(){}.getType();
//                Map<String, String> map1 = gson.fromJson(json, type);
                log.info("唤起支付参数:{}", JSON.toJSONString(map));
                return ResultUtil.data(map);
            }
            log.error("微信支付参数验证错误，请及时处理");
            throw new ServiceException(ResultCode.PAY_ERROR);
        } catch (Exception e) {
            log.error("支付异常", e);
            throw new ServiceException(ResultCode.PAY_ERROR);
        }
    }


    public String getOpenId(String code) {
        String url = WEB_GET_ACCESS_TOKEN.replace("APPID", appId).replace("SECRET", secret).replace("CODE", code);
        String body = HttpUtil.createGet(url)
                .execute()
                .body();
        log.info("获取了token,返回数据 body:{} ", body);
        com.alibaba.fastjson.JSONObject object = JSON.parseObject(body);
        //获取 openId
        String openId = object.getString("openid");
        log.info(".getOpenId:{}", openId);
        return openId;
    }

    @Override
    public ResultMessage<Object> jsDfApiPay(DFPayParam payParam) {

        try {

            String orderSn = payParam.getOrderSn();
            Payer payer = new Payer();
//            UserNameAndFaceVO userNameAndFaceByOrderSn = orderService.getUserNameAndFaceByOrderSn(orderSn);
//
//            log.info(".jsApiPay userNameAndFaceByOrderSn:{}", userNameAndFaceByOrderSn);
//            payer.setOpenid(userNameAndFaceByOrderSn.getOpenId());


            com.alibaba.fastjson.JSONObject resultObj = null;
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code".replace("APPID", "wx0fa1500017b8f6f1").replace("SECRET", secret).replace("CODE", payParam.getUserCode());
            log.info(".jsDfApiPay url:{}", url);
            com.alibaba.fastjson.JSONObject accessTokenObj = getJsonData(url);
            log.info(".jsDfApiPay accessTokenObj={}", accessTokenObj);
            if (accessTokenObj != null && accessTokenObj.get("access_token") != null) {
                String openId = accessTokenObj.getString("openid");
                log.info(".jsDfApiPay openId:{}", openId);
                payer.setOpenid(openId);
            }

//            payer.setOpenid(payParam.getOpenId());
            // 写死
//            payer.setOpenid("oaqct6wRkSLz20Xk77oGc7zDjHms");
            Order order = orderService.getOrder(orderSn);
            log.info(".jsApiPay order:{}", order);


            //支付金额
            Integer fen = CurrencyUtil.fen(order.getFlowPrice());
            //第三方付款订单
            String outOrderNo = SnowFlake.createStr("pay_");

            // 将payOrder 更新到订单中
            orderService.updatePayOrderSnByOrderSn(orderSn, outOrderNo);

            //过期时间
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);

            String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(payParam), StandardCharsets.UTF_8);


            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(appid)
                    .setMchid(mchId)
                    .setDescription("aa")
                    .setOut_trade_no(outOrderNo)
                    .setTime_expire(timeExpire)
                    .setAttach(attach)
                    .setNotify_url(NOTIFY_URL)
                    .setAmount(new Amount().setTotal(fen))
                    .setPayer(payer);

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            PaymentHttpResponse response = WechatApi.v3(
                    RequestMethodEnums.POST,
                    WechatDomain.CHINA.toString(),
                    WechatApiEnum.JS_API_PAY.toString(),
                    mchId,
                    serialNumber,
                    null,
                    appliclient_key,
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            //根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, getPlatformCert());
            log.info("verifySignature: {}", verifySignature);
            log.info("统一下单响应 {}", response);

            if (verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, appliclient_key);


//                String json = "{\"timeStamp\":\"1707227342\",\"signType\":\"RSA\",\"package\":\"prepay_id=wx062149024993563e099438072054070000\",\"paySign\":\"0b00/0rNFkVpKWZhVDzZwPzbGjiedSOmhZ544iwmoh9ocmTOigYD06H9X5pTgQ58GUrXfSO8Z7xRdmU2gGfZIQx8KUXbYKuCjdfMEWK+GCZ8K7qU2cv7l2ulxbVCgKyYrFIhUED2sdIJV2bT19yaGeToDI6rqP92TpVIlRiip5Xe9/5YTqyi7e7Mg0+JpvlsnUkPfxCO5UJvc0jh/Gd94FwaJhVA8F53DWjzX5sIIREoqujNlVqARLS1ypGZWuPPwunOUMtpj9uWO5oaF3thwmOT0zyned/gUMNNZxezQwRr83uGV4VhGySo1ElNsdXYZdS4f5Fu8OQSxoFpgrPJIg==\",\"nonceStr\":\"1707227342156\",\"appId\":\"wx0fa1500017b8f6f1\"}";
//
//
//                Gson gson = new Gson();
//                Type type = new TypeToken<Map<String, String>>(){}.getType();
//                Map<String, String> map1 = gson.fromJson(json, type);
                log.info("唤起支付参数:{}", JSON.toJSONString(map));
                return ResultUtil.data(map);
            }
            log.error("微信支付参数验证错误，请及时处理");
            throw new ServiceException(ResultCode.PAY_ERROR);
        } catch (Exception e) {
            log.error("支付异常", e);
            throw new ServiceException(ResultCode.PAY_ERROR);
        }
    }

    @Override
    public void verifyNotify(HttpServletRequest request) throws Exception {
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String serialNo = request.getHeader("Wechatpay-Serial");
        String signature = request.getHeader("Wechatpay-Signature");

        log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
        String result = HttpKit.readData(request);
        log.info("微信支付通知密文 {}", result);

        WechatPaymentSetting setting = wechatPaymentSetting();
        //校验服务器端响应¬
        String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                setting.getApiKey3(), Objects.requireNonNull(getPlatformCert()));

        log.info("微信支付通知明文 {}", plainText);

        JSONObject jsonObject = JSONUtil.parseObj(plainText);
        log.info(".verifyNotify jsonObject :{}", JSON.toJSONString(jsonObject));
        String payParamStr = jsonObject.getStr("attach");
        log.info(".verifyNotify payParamStr :{}", JSON.toJSONString(payParamStr));
        String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8);
        log.info(".verifyNotify payParamJson :{}", JSON.toJSONString(payParamJson));
        PayParam payParam = JSONUtil.toBean(payParamJson, PayParam.class);
        log.info(".verifyNotify payParam :{}", JSON.toJSONString(payParam));
        String out_trade_no = jsonObject.getStr("out_trade_no");
        log.info(".verifyNotify out_trade_no :{}", out_trade_no);
        String tradeNo = jsonObject.getStr("transaction_id");
        log.info(".verifyNotify tradeNo :{}", tradeNo);
        Double totalAmount = CurrencyUtil.reversalFen(jsonObject.getJSONObject("amount").getDouble("total"));
        log.info(".verifyNotify tradeNo:{} totalAmount:{}", tradeNo, totalAmount);
        String trade_state = jsonObject.getStr("trade_state");
        log.info(".verifyNotify trade_state :{}", trade_state);
        Date successTime = jsonObject.getDate("success_time");
        log.info(".verifyNotify success_time :{}", successTime);
        if (trade_state.equals("SUCCESS")) {
            PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
                    PaymentMethodEnum.WECHAT.name(),
                    tradeNo,
                    totalAmount,
                    payParam,
                    successTime
            );
            log.info(".verifyNotify paymentSuccessParams :{}", JSON.toJSONString(paymentSuccessParams));
            this.success(paymentSuccessParams);
        }
    }

    @Override
    public Boolean query(String orderSn) {
        Order order = orderService.getOrder(orderSn);
        if (null != order && order.getPayStatus().equals(PayStatusEnum.PAID)) {
            return true;
        }
        return false;
    }

    private void success(PaymentSuccessParams paymentSuccessParams) {
        String receivableNo = paymentSuccessParams.getReceivableNo();
        PayParam payParam = paymentSuccessParams.getPayParam();
        Double price = paymentSuccessParams.getPrice();
        String orderSn = payParam.getOrderSn();
        // 核对金额
        Order orderBySn = orderService.getOrder(orderSn);
        if (null == orderBySn) {
            throw new RuntimeException("不存在该订单");
        }
        Double flowPrice = orderBySn.getFlowPrice();
        if (price.equals(flowPrice)) {
            orderService.updatePayStatusByOrderSn(orderSn, receivableNo, paymentSuccessParams.getSuccessTime(), PayStatusEnum.PAID);
            log.info(".success 微信回调更新订单状态完成");
        } else {
            log.error(".PayError 支付金额有误 订单金额为:{} 回调回来的金额为:{}", flowPrice, price);
        }
    }

    /**
     * 获取平台公钥
     *
     * @return 平台公钥
     */
    private X509Certificate getPlatformCert() {
        //获取缓存中的平台公钥，如果有则直接返回，否则去微信请求
        String publicCert = null;
        //获取平台证书列表
        try {

            WechatPaymentSetting setting = wechatPaymentSetting();

            PaymentHttpResponse response = WechatApi.v3(
                    RequestMethodEnums.GET,
                    WechatDomain.CHINA.toString(),
                    WechatApiEnum.GET_CERTIFICATES.toString(),
                    setting.getMchId(),
                    setting.getSerialNumber(),
                    null,
                    setting.getApiclient_key(),
                    ""
            );
            String body = response.getBody();
            log.info("获取微信平台证书body: {}", body);
            if (response.getStatus() == 200) {
                JSONObject jsonObject = JSONUtil.parseObj(body);
                JSONArray dataArray = jsonObject.getJSONArray("data");
                //默认认为只有一个平台证书
                JSONObject encryptObject = dataArray.getJSONObject(0);
                JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
                String associatedData = encryptCertificate.getStr("associated_data");
                String cipherText = encryptCertificate.getStr("ciphertext");
                String nonce = encryptCertificate.getStr("nonce");
                publicCert = getPlatformCertStr(associatedData, nonce, cipherText);
            } else {
                log.error("证书获取失败：{}" + body);
                throw new ServiceException(ResultCode.WECHAT_CERT_ERROR);
            }
            return PayKit.getCertificate(publicCert);
        } catch (Exception e) {
            log.error("证书获取失败", e);
        }
        return null;
    }

    /**
     * 获取平台证书缓存的字符串
     * 下列各个密钥参数
     *
     * @param associatedData 密钥参数
     * @param nonce          密钥参数
     * @param cipherText     密钥参数
     * @return platform key
     * @throws GeneralSecurityException 密钥获取异常
     */
    private String getPlatformCertStr(String associatedData, String nonce, String cipherText) throws GeneralSecurityException {


        AesUtil aesUtil = new AesUtil(wechatPaymentSetting().getApiKey3().getBytes(StandardCharsets.UTF_8));
        //平台证书密文解密
        //encrypt_certificate 中的  associated_data nonce  ciphertext
        return aesUtil.decryptToString(
                associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                cipherText
        );
    }

    /**
     * 获取微信支付配置
     *
     * @return
     */
    private WechatPaymentSetting wechatPaymentSetting() {
        try {
            WechatPaymentSetting wechatPaymentSetting = new WechatPaymentSetting();
            wechatPaymentSetting.setApiKey3(ApiKey3);
            wechatPaymentSetting.setMchId(mchId);
            wechatPaymentSetting.setApiclient_key(appliclient_key);
            wechatPaymentSetting.setSerialNumber(serialNumber);
            return wechatPaymentSetting;
        } catch (Exception e) {
            log.error("微信支付暂不支持", e);
            throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
        }
    }

    /**
     * 发起get请求
     * @param url
     * @return
     */
    public com.alibaba.fastjson.JSONObject getJsonData(String url) {
        RestTemplate restTemplate = new RestTemplate();
        // 设置 HTTP 头部信息
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Accept-Charset", "UTF-8");
        // 创建 StringHttpMessageConverter 并设置编码方式为 UTF-8
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        stringHttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
        restTemplate.getMessageConverters().add(0, stringHttpMessageConverter);
        // 发送 GET 请求，并将响应映射为 JSONObject
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        // 获取响应中的 JSONObject
        com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(responseEntity.getBody());
        return jsonObject;
    }

    public String getOpenId2(String code){
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appid+"&secret="+secret+"&code="+code+"&grant_type=authorization_code";
        String body = HttpUtil.createGet(url)
                .execute()
                .body();
        log.info("获取了getOpenId2,返回数据 userOpenId:{} ", body);
        com.alibaba.fastjson.JSONObject object = JSON.parseObject(body);
        //获取token
        return object.getString("openid");
    }
}
